package org.lcc.Service.impl;

import org.lcc.Service.UserService;
import org.lcc.config.KeyLoader;
import org.lcc.mapper.UserMapper;
import org.lcc.model.entity.StudentMistakeEntity;
import org.lcc.model.VO.UserDtoVO;
import org.lcc.model.dto.*;
import org.lcc.model.entity.BadRequestException;
import org.lcc.model.entity.BusinessException;
import org.lcc.model.entity.User;
import org.lcc.util.JwtUtil;
import org.lcc.util.RSAUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.security.PrivateKey;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class UserServiceImpl implements UserService {
    // 从配置文件中加载RSA公钥和私钥
    @Value("${rsa.publicKey}")
    private String publicKeyBase64;

    @Value("${rsa.privateKey}")
    private String privateKeyBase64;

    // RSA私钥
    private PrivateKey privateKey;

    // 密码加密器，用于校验密码
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private UserMapper userMapper;

    // 初始化RSA密钥
    @PostConstruct
    public void initKeys() throws Exception {
        privateKey = KeyLoader.loadPrivateKey(privateKeyBase64);
    }

    // 登录
    /**
     * 用户登录方法
     *
     * 该方法接收一个登录请求，验证验证码，用户名和密码，并在登录成功后返回用户信息和令牌
     * 如果验证码错误、用户名不存在或密码不匹配，将抛出业务异常
     * 如果系统内部发生错误，将抛出系统内部错误异常
     *
     * @param request 包含用户名、密码和验证码信息的登录请求对象
     * @return 登录成功后的用户信息和令牌
     * @throws BusinessException 当用户名或密码错误时抛出的业务异常
     * @throws Exception 当系统内部发生错误时抛出的异常
     */
    @Override
    public UserDto login(LoginRequest request) {
        try {
            // 验证验证码的正确性
            validateVerifyCode(request.getVerifyCodeKey(), request.getVerifyCode());

            // 根据用户名查询用户信息
            User user = userMapper.login(request.getUsername());

            // 如果用户信息为空，抛出业务异常
            if (user == null) {
                throw new BusinessException(400, "用户名或密码错误");
            }
            //判断该用户是否加入了班级，如何未加入则抛出异常
            List <Integer> classId = userMapper.selectClassByUserId(user.getSchoolNumber());
            if (classId.isEmpty()||classId==null){
                throw new BusinessException(400, "用户未加入班级,暂时无法登录,请联系老师加入班级");
            }
            // 解密密码并验证密码的正确性
            String plainPassword = decryptPassword(request.getPassword());
            System.out.println("plainPassword: " + plainPassword);
            if (!bCryptPasswordEncoder.matches(plainPassword, user.getPassword())) {
                throw new BusinessException(400, "用户名或密码错误");
            }

            // 生成令牌并构建用户DTO对象返回
            String token = jwtUtil.generateToken(user.getUsername());
            UserDto userDto = new UserDto();
            userDto.setRole(user.getRole().name());
            userDto.setUsername(user.getUsername());
            userDto.setPassword(user.getPassword());
            userDto.setEmail(user.getEmail());
            userDto.setRealName(user.getRealName());
            userDto.setSchoolNumber(user.getSchoolNumber());
            userDto.setToken(token);
            userDto.setCreateTime(user.getCreateTime());
            return userDto;
        } catch (BusinessException e) {
            // 打印业务异常堆栈并重新抛出异常
            e.printStackTrace();
            throw e;
        } catch (Exception e) {
            // 打印系统内部错误异常堆栈并抛出新的业务异常
            e.printStackTrace();
            throw new BusinessException(500, "系统内部错误");
        }
    }

    // 注册
    @Override
    public Boolean signin(Sign_inRequest signInRequest) {
        try {
            validateVerifyCode(signInRequest.getVerifyCodeKey(), signInRequest.getVerifyCode());
            System.out.println("sign_inRequest: " + signInRequest);
            String plainPassword = decryptPassword(signInRequest.getPassword());
            String hashedPassword = bCryptPasswordEncoder.encode(plainPassword);
            signInRequest.setPassword(hashedPassword);
            return userMapper.signin(signInRequest);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(400, "注册失败，用户名或者学号重复");
        }
    }

    // 重置密码
    @Override
    public Boolean forget(String schoolNumber, String username, String newPassword, String verifyCode, String verifyCodeKey) {
        try {
            validateVerifyCode(verifyCodeKey, verifyCode);
            User user = userMapper.forget(schoolNumber, username);
            if (user == null) {
                throw new BusinessException(400, "身份验证不通过");
            }
            String plainPassword = decryptPassword(newPassword);
            String hashedPassword = bCryptPasswordEncoder.encode(plainPassword);
            int i = userMapper.editPassword(hashedPassword, schoolNumber);
            return i > 0;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(400, "重置密码失败");
        }
    }

    // 创建班级
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean createClass(CreateRequest createRequest) {
        try {
            userMapper.createClass(createRequest);
            if (createRequest.getClassId() == null) {
                throw new BusinessException(400, "创建班级失败");
            }
            int i = 0;
            if (createRequest.getClassId() > 0) {
                i = userMapper.createteacher_class(createRequest.getTeacherNumber(), createRequest.getClassId());
            }
            return i > 0;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(400, "创建班级失败");
        }
    }
//批量导入
    @Override
    @Transactional
    public boolean batchInsertion(List<Sign_inRequest> dataList,Integer classId) {
        try {
            dataList.forEach(user -> {
                user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
            });
            userMapper.batchInsertUsers(dataList);
            userMapper.insertstudent_class_link(dataList,classId);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(400,"批量导入失败");
        }
    }
    //更新用户信息
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateUser(UserDto userDto) {
        try {
            Boolean updateUser = userMapper.updateUser(userDto);
            if (updateUser) {
                return true;
            }
            return false;
        } catch (DataIntegrityViolationException e) {
            if (e.getCause() instanceof SQLIntegrityConstraintViolationException) {
                SQLIntegrityConstraintViolationException sqlException = (SQLIntegrityConstraintViolationException) e.getCause();
                if (sqlException.getErrorCode() == 1062) {
                    throw new BusinessException(400, "用户名已经存在");
                }
            }
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(500, "更新用户时发生未知错误");
        }
    }

    @Override
    public UserDtoVO getStudentList(String teacherNumber) {
        try {
            // 先通过工号查询班级
            List<Integer> classes = userMapper.getClassByTeacherNumberList(teacherNumber);
            if (classes.isEmpty()) {
                return null;
            }

            // 班级 ID 查询学生
            List<UserDto> userDtoList = userMapper.getStudentList(classes);
            int userCount = userDtoList.size();
            UserDtoVO userDtoVO = new UserDtoVO(userCount, userDtoList);
            return userDtoVO;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(500, "获取学生列表时发生未知错误");
        }
    }

    @Override
    public List<ClassInfoDto> getClassByTeacherNumber(String teacherNumber) {
        try {
            System.out.println("teacherNumber: " + teacherNumber);
            List<ClassInfoDto> classByTeacherNumber = userMapper.getClassByTeacherNumber(teacherNumber);
            System.out.println("classByTeacherNumber: " + classByTeacherNumber);
            return classByTeacherNumber;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(500, "获取班级列表时发生未知错误");
        }
    }

    /**
     * 验证验证码
     *
     * @param verifyCodeKey 验证码的唯一键
     * @param verifyCode    用户输入的验证码
     * @throws BadRequestException 验证码错误或过期
     */
    public void validateVerifyCode(String verifyCodeKey, String verifyCode) throws BusinessException {
        System.out.println("verifyCodeKey: " + verifyCodeKey);
        String storedVerifyCode = redisTemplate.opsForValue().get(verifyCodeKey);
        System.out.println("storedVerifyCode: " + storedVerifyCode);
        if (storedVerifyCode == null || !storedVerifyCode.equalsIgnoreCase(verifyCode)) {
            throw new BusinessException(400, "验证码失效或错误");
        }
        redisTemplate.delete(verifyCodeKey);
    }

    /**
     * 解密密码
     *
     * @param encryptedPassword 加密后的密码
     * @return 解密后的明文密码
     * @throws Exception 如果解密失败
     */
    private String decryptPassword(String encryptedPassword) throws Exception {
        return RSAUtil.decrypt(encryptedPassword, privateKey);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addStudent(AddStudentRequest request) {
        try {
            // 加密密码
            String hashedPassword = bCryptPasswordEncoder.encode(request.getPassword());
            request.setPassword(hashedPassword);
            System.out.println(request);
            // 新增考生
            Boolean result = userMapper.addStudent(request);
            if (!result) {
                throw new BusinessException(400, "新增考生失败");
            }
            
            // 新增考生班级关联
            result = userMapper.addStudentClassLink(request.getSchool_number(), request.getClass_id());
            if (!result) {
                throw new BusinessException(400, "新增考生班级关联失败");
            }
            
            return true;
        } catch (DataIntegrityViolationException e) {
            if (e.getCause() instanceof SQLIntegrityConstraintViolationException) {
                SQLIntegrityConstraintViolationException sqlException = (SQLIntegrityConstraintViolationException) e.getCause();
                if (sqlException.getErrorCode() == 1062) {
                    throw new BusinessException(400, "用户名或学号已存在");
                }
            }
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(500, "新增考生时发生未知错误");
        }
    }

    @Override
    public Map<String, Object> filterStudentsByClass(String teacherNumber, Integer classId, String keyword, String status, int offset, int pageSize) {
        // 获取筛选后的学生列表和总数
        List<UserDto> studentList = userMapper.filterStudentsByClass(teacherNumber, classId, keyword, status, offset, pageSize);
        Integer total = userMapper.getFilteredStudentCount(teacherNumber, classId, keyword, status);

        Map<String, Object> result = new HashMap<>();
        result.put("list", studentList);
        result.put("total", total);
        return result;
    }

    @Override
    public Boolean deleteStudent(String schoolNumber) {
        try {
            // 1. 删除学生与班级的关联关系
            Integer e =userMapper.deleteBySchoolNumber_Class(schoolNumber);

            // 2. 删除学生的考试记录
            Integer w =userMapper.deleteBySchoolNumber_Exam(schoolNumber);

            // 3. 删除学生的答题记录
           Integer q= userMapper.deleteBySchoolNumber_question(schoolNumber);

            // 4. 删除学生的考试通知记录
            Integer i =userMapper.deleteBySchoolNumber_Ecamlist(schoolNumber);
//
            // 5. 最后删除学生用户信息
            int result = userMapper.deleteBySchoolNumber(schoolNumber);
            return result > 0;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(500, "删除学生失败：" + e.getMessage());
        }
    }

    @Override
    public void activateStudents(List<String> schoolNumbers) {
        try {
            userMapper.activateStudents(schoolNumbers);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(500, "激活学生失败：" + e.getMessage());
        }
    }

    @Override
    public void disableStudents(List<String> schoolNumbers) {
        try {
            userMapper.disableStudents(schoolNumbers);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(500, "禁用学生失败：" + e.getMessage());
        }
    }

    @Override
    public void resetStudentsPassword(List<String> schoolNumbers, String newPassword) throws Exception {
        try {
            // 解密新密码
            String plainPassword = decryptPassword(newPassword);
            // 加密新密码
            String hashedPassword = bCryptPasswordEncoder.encode(plainPassword);
            // 批量更新密码
            userMapper.resetStudentsPassword(schoolNumbers, hashedPassword);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(500, "重置密码失败：" + e.getMessage());
        }
    }

    @Override
    public void moveStudentsClass(List<String> schoolNumbers, Integer targetClassId) {
        try {
            // 先删除原有的班级关联
            userMapper.deleteStudentsClassLinks(schoolNumbers);
            // 添加新的班级关联
            userMapper.insertStudentsClassLinks(schoolNumbers, targetClassId);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(500, "移动班级失败：" + e.getMessage());
        }
    }

    @Override
    public Map<String, Object> getStudentClass(String schoolNumber) {
        try {
            return userMapper.getStudentClass(schoolNumber);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(500, "获取学生班级信息失败：" + e.getMessage());
        }
    }

    @Override
    public List<StudentMistakeEntity> getWrongQuestionList() {
        return userMapper.getWrongQuestionList();
    }
}